package com.minivision.sdktestdemo.ui.custom;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;

import com.minivision.sdktestdemo.R;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2016/7/25.
 */
public class LrcScrollView extends View {
    private int mNormalTextColor;
    private int mFocusTextColor;
    private LrcProvider mProvider;
    private int mTextSize;
    private Paint mNormalTextPaint;
    private Paint mFocusTextPaint;
    private List<LrcTextInfo> mLrcList;
    private int mPadding = 16;
    private int mTextMargin = 0;
    private int mBegTextOffSetY;
    private Scroller mScroller;
    private int mMaxScrollY;
    private int mPresent;
    private String mEmptyText = "正在加载歌词,请稍后....";
    private boolean isAutoScrolled;

    class LrcTextInfo {
        int height;
        int pos;
        long time;
        List<Integer> widths = new ArrayList<>();
        String text;
        List<Integer> lens = new ArrayList<>();
    }

    public LrcScrollView(Context context) {
        super(context);
    }

    public LrcScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public LrcScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }


    public void displayPresentLrc(long time) {
        if (!mLrcList.isEmpty()) {
            int pos = getPresentLrc(time);
            if (pos != mPresent && isAutoScrolled) {
                smoothScrollTo(pos);
                mPresent = pos;
            }
        }
    }

    private int getPresentLrc(long time) {
        int left = 0;
        int right = mLrcList.size();
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (mLrcList.get(mid).time > time) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        return left != 0 ? left - 1 : left;
    }

    public void smoothScrollTo(int position) {
        int y = mLrcList.get(position).pos;
        int begin = mLrcList.get(0).pos;
        mScroller.startScroll(getScrollX(), getScrollY(), 0, y - getScrollY() - begin, 500);
        postInvalidate();
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            postInvalidate();
        }
    }

    public interface LrcProvider {
        List<String> getLrcList();
        List<Long> getLrcTimeList();
    }

    public void clearLrcList(String text) {
        mEmptyText = text;
        mLrcList.clear();
        requestLayout();
        postInvalidate();
    }

    public void init(Context context, AttributeSet attributeSet) {
        mNormalTextPaint = new Paint();
        mFocusTextPaint = new Paint();
        TypedArray tp = context.obtainStyledAttributes(attributeSet, R.styleable.LrcScrollView);
        mNormalTextColor = tp.getColor(R.styleable.LrcScrollView_normalTextColor, 1);
        mFocusTextColor = tp.getColor(R.styleable.LrcScrollView_focusTextColor, 1);
        mTextSize = tp.getDimensionPixelSize(R.styleable.LrcScrollView_textSize,
                (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, context.getResources().getDisplayMetrics()));
        mTextMargin = tp.getDimensionPixelSize(R.styleable.LrcScrollView_textMargin,
                (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, context.getResources().getDisplayMetrics()));
        mFocusTextPaint.setColor(mFocusTextColor);
        mNormalTextPaint.setColor(mNormalTextColor);
        mFocusTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
        mNormalTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
        tp.recycle();

        mNormalTextPaint.setTextSize(mTextSize);
        mFocusTextPaint.setTextSize(mTextSize);
        mLrcList = new ArrayList<>();
        mScroller = new Scroller(context);
    }

    public void calcTextHeight() {
        int index = 0;
        for (LrcTextInfo info : mLrcList) {
            int width = (int) mNormalTextPaint.measureText(info.text);
            int contenWidth = getWidth() - getPaddingLeft() - getPaddingRight();
            int len = (width - 1) / contenWidth + 1;
            int w = (int) mNormalTextPaint.measureText(info.text, 0, 1);
            info.lens.clear();
            info.widths.clear();
            int l = 0;
            for (int i = 0; i < len; ++i) {
                if (i == len - 1) {
                    info.lens.add(info.text.length() - l);
                } else {
                    info.lens.add(contenWidth / w);
                }
                info.widths.add((int) mNormalTextPaint.measureText(info.text, l, l + info.lens.get(i)));
                l += info.lens.get(i);
            }
            info.height = mTextSize * info.lens.size() + (info.lens.size() - 1) * mPadding;
            info.pos = index == 0 ? mBegTextOffSetY : mLrcList.get(index - 1).pos + mTextMargin + mLrcList.get(index).height;
            ++index;
        }
    }

    @Override
    public void scrollBy(int x, int y) {
        int temp = getScrollY() - y;
        temp = Math.max(0, temp);
        temp = Math.min(mMaxScrollY, temp);
        y = temp - getScrollY();
        Log.i("scroll", "scrollBy: "  + temp + "," + mMaxScrollY);
        if (y != 0) {
            super.scrollBy(x, y);
        }
    }

    public void setLrcView(LrcProvider provider) {
        mProvider = provider;
        mLrcList.clear();
        isAutoScrolled = true;
        for (int i = 0; i < mProvider.getLrcList().size(); ++i) {
            LrcTextInfo info = new LrcTextInfo();
            info.text = mProvider.getLrcList().get(i);
            info.time = mProvider.getLrcTimeList().get(i);
            mLrcList.add(info);
        }
        requestLayout();
        postInvalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int wSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int wSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int hSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int hSpecSize = MeasureSpec.getSize(heightMeasureSpec);

        if (wSpecMode == MeasureSpec.AT_MOST && hSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(wSpecSize, (mTextSize + 2 * mTextMargin));
        } else if (wSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(wSpecSize, hSpecSize);
        } else if (hSpecMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(wSpecSize, (mTextSize + 2 * mTextMargin));
        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        mBegTextOffSetY = getHeight() / 2;
        if (!mLrcList.isEmpty()) {
            calcTextHeight();
            mMaxScrollY = mLrcList.get(mLrcList.size() - 1).pos - getHeight() / 2;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int contentWidth = getWidth() - getPaddingRight() - getPaddingLeft();
        if (mLrcList.isEmpty()) {
            int width = (int) mFocusTextPaint.measureText(mEmptyText);
            mMaxScrollY = mBegTextOffSetY;
            canvas.drawText(mEmptyText, (contentWidth - width) / 2, mBegTextOffSetY, mFocusTextPaint);
            return;
        }
        int pos = 0;
        Log.i("pos", "onDraw: " + mPresent);
        for (LrcTextInfo info : mLrcList) {
            int len = 0;
            Paint paint = pos++ == mPresent ? mFocusTextPaint : mNormalTextPaint;
            for (int i = 0; i < info.lens.size(); ++i) {
                int offset = info.lens.size() - i - 1;
                canvas.drawText(info.text,
                        len, len + info.lens.get(i),
                        (contentWidth - info.widths.get(i)) / 2, info.pos - offset * (mTextSize + mPadding),
                        paint);
                len += info.lens.get(i);
            }
        }
    }

    private float mPrevY;
    private boolean isClicked;
    private float mSrcY;
    private float mMinLen = 10;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                isClicked = true;
                isAutoScrolled = false;
                mPrevY = event.getY();
                mSrcY = mPrevY;
                Log.i("event", "onTouch: " + event.getRawX() + ", " + event.getRawY());
                break;
            case MotionEvent.ACTION_MOVE:
                scrollBy(0, (int) (event.getY() - mPrevY));
                mPrevY = event.getY();
                if (Math.abs(mSrcY - mPrevY) >= mMinLen) {
                    isClicked = false;
                }
                break;
            case MotionEvent.ACTION_UP:
                isAutoScrolled = true;
                if (!isClicked) {
                    return true;
                }
        }
        return super.onTouchEvent(event);
    }
}